package org.vs.handler.responsibilitychain.vote;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.apache.commons.net.util.Base64;
import org.springframework.stereotype.Component;
import org.vs.annotation.CheckBalance;
import org.vs.contract.VoteContract;
import org.vs.domain.model.SysUser;
import org.vs.domain.model.TUserVote;
import org.vs.domain.vo.ProgressVO;
import org.vs.handler.responsibilitychain.BaseResponsibilityChainHandler;
import org.vs.mapper.TUserVoteMapper;
import org.vs.mapper.TVoteMapper;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;

@Component
public class VotePublishUserHandler extends BaseResponsibilityChainHandler {
    @Resource
    private TVoteMapper voteMapper;

    @Resource
    private TUserVoteMapper userVoteMapper;

    @Resource
    private VotePublishTransmitUserInfoHandler voteTransmitUserInfoHandler;

    @CheckBalance
    @Override
    protected boolean customerHandler(Object obj) {
        try {
            VotePublishHandlerEO votePublishHandlerEO = (VotePublishHandlerEO) obj;

            votePublishHandlerEO.setCount(votePublishHandlerEO.getCount() + 1);
            setHandler(voteTransmitUserInfoHandler);
            setMessage(votePublishHandlerEO.getHashcode(), JSON.toJSONString(ProgressVO
                    .builder()
                    .progress((100 / voteCount) * votePublishHandlerEO.getCount())
                    .info("完成选民信息写入")
                    .build()));

            List<SysUser> users = voteMapper.selectUserInVoteByVoteId(
                    votePublishHandlerEO.getVote().getVoteId());
            List<VoteContract.Elector> voteElectors = new ArrayList<>();
            List<TUserVote> userVotes = new ArrayList<>();

            for (SysUser user : users) {
                String[] keyInfos = createKey();

                String sign = sign(user.getAddress(), keyInfos[1]);

                voteElectors.add(new VoteContract.Elector(
                        BigInteger.valueOf(user.getUserId()),
                        sign,
                        BigInteger.valueOf(1L)));

                userVotes.add(TUserVote
                        .builder()
                        .userId(user.getUserId())
                        .voteId(votePublishHandlerEO.getVote().getVoteId())
                        .hashcode(keyInfos[0])
                        .build());
            }

            for (TUserVote userVote : userVotes) {
                userVoteMapper.update(userVote, new UpdateWrapper<TUserVote>()
                        .eq("user_id", userVote.getUserId())
                        .eq("vote_id", userVote.getVoteId()));
            }

            votePublishHandlerEO.getVoteContract().setElector(voteElectors).send();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    /**
     * 给每个用户创建公钥和私钥
     * @return
     * @throws NoSuchAlgorithmException
     */
    private String[] createKey() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 生产公钥
        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
        String clientPublicKey = Base64.encodeBase64String(publicKey.getEncoded());
        // 生产私钥
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
        String clientPrivateKey = Base64.encodeBase64String(privateKey.getEncoded());

        return new String[]{clientPublicKey, clientPrivateKey};
    }

    /**
     * 签名
     * @param data
     * @param privateKey
     * @return
     */
    public static String sign(String data, String privateKey) {
        try {
            byte[] dataBytes = data.getBytes();
            byte[] keyBytes = Base64.decodeBase64(privateKey);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey1 = keyFactory.generatePrivate(keySpec);
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(privateKey1);
            signature.update(dataBytes);
            return Base64.encodeBase64String(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
